/**
 * Author: Brent Myers
 * Time-stamp: <2008-07-23 16:59:35 bam>
 * 
 * Templated Collision Strategy Tests
 * 
 */

#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>

#include <boost/mpl/list.hpp>

using boost::unit_test::test_suite;

// STL
#include <iostream>


#include "src/LinearProbe.h"
#include "src/SimpleHash.h"
#include "src/genhash.h"
#include "src/ModuloHash.h"
#include "src/BitmaskHash.h"
#include "src/Chaining.h"

#include <utility>

using std::make_pair;
using std::pair;

using namespace genhash;

BOOST_TEST_CASE_TEMPLATE_FUNCTION( cs1 , CS )
{
	CS ht;
	ht.insert(make_pair(1, 2));
	typename CS::iterator it(ht.find(1));
	BOOST_CHECK_EQUAL(it->first, 1);
	BOOST_CHECK_EQUAL(it->second, 2);
}


BOOST_TEST_CASE_TEMPLATE_FUNCTION( cs2 , CS )
{
	CS ht;
	ht.insert(make_pair(1, 2));
	ht.insert(make_pair(3, 4));

	typename CS::iterator it1(ht.find(1));
	BOOST_CHECK_EQUAL(it1->first, 1);
	BOOST_CHECK_EQUAL(it1->second, 2);

	typename CS::iterator it2(ht.find(3));
	BOOST_CHECK_EQUAL(it2->first, 3);
	BOOST_CHECK_EQUAL(it2->second, 4);

}

BOOST_TEST_CASE_TEMPLATE_FUNCTION( cs3 , CS )
{
	CS ht;
	ht.insert(make_pair(1, 2));
	ht.insert(make_pair(11, 12));

	typename CS::iterator it1(ht.find(1));
	BOOST_CHECK_EQUAL(it1->first, 1);
	BOOST_CHECK_EQUAL(it1->second, 2);

	typename CS::iterator it2(ht.find(11));
	BOOST_CHECK_EQUAL(it2->first, 11);
	BOOST_CHECK_EQUAL(it2->second, 12);

}

BOOST_TEST_CASE_TEMPLATE_FUNCTION( cs4 , CS )
{
	CS ht;
	ht.insert(make_pair(1, 2));
	ht.insert(make_pair(11, 12));

	typename CS::iterator it1(ht.find(1));
	BOOST_CHECK_EQUAL(it1->first, 1);
	BOOST_CHECK_EQUAL(it1->second, 2);

	typename CS::iterator it2(ht.find(11));
	BOOST_CHECK_EQUAL(it2->first, 11);
	BOOST_CHECK_EQUAL(it2->second, 12);

}

BOOST_TEST_CASE_TEMPLATE_FUNCTION( cs5 , CS )
{
	CS ht;
	BOOST_CHECK_NO_THROW(ht.insert(make_pair(1, 2)));
	BOOST_CHECK_NO_THROW(ht.insert(make_pair(11, 12)));
	if(ht.max_size() < 3) 
		BOOST_CHECK_THROW(ht.insert(make_pair(4, 5)), HashtableFullException);
}

BOOST_TEST_CASE_TEMPLATE_FUNCTION( cs6 , CS )
{
	CS ht;
	ht.insert(make_pair(1, 2));

	typename CS::iterator it1(ht.find(1));
	BOOST_CHECK_EQUAL(it1->first, 1);
	BOOST_CHECK_EQUAL(it1->second, 2);

	ht.insert(make_pair(1, 12));

	typename CS::iterator it2(ht.find(1));
	BOOST_CHECK_EQUAL(it2->first, 1);
	BOOST_CHECK_EQUAL(it2->second, 2);

}

BOOST_TEST_CASE_TEMPLATE_FUNCTION( cs7 , CS )
{
	CS ht;
	ht.insert(make_pair(1, 2));

	typename CS::iterator it1(ht.find(2));
	BOOST_CHECK(it1 == ht.end());
}

BOOST_TEST_CASE_TEMPLATE_FUNCTION( cs8 , CS )
{
	CS ht;
	typedef typename CS::iterator iter;
	pair<iter, bool> ret = ht.insert(make_pair(1, 2));
	BOOST_CHECK_EQUAL(ret.first->first, 1);
	BOOST_CHECK_EQUAL(ret.first->second, 2);
	BOOST_CHECK_EQUAL(ret.second, true);
}

BOOST_TEST_CASE_TEMPLATE_FUNCTION( cs9 , CS )
{
	CS ht;
	typedef typename CS::iterator iter;
	ht.insert(make_pair(1,2));
	pair<iter, bool> ret = ht.insert(make_pair(1, 3));
	BOOST_CHECK_EQUAL(ret.first->first, 1);
	BOOST_CHECK_EQUAL(ret.first->second, 2);
	BOOST_CHECK_EQUAL(ret.second, false);
}



struct LPTestConfig1 
{
	enum { max_size = 10 };
	typedef int KeyType;
	typedef int DataType;
	typedef SimpleHash<LPTestConfig1> HashFn;
	typedef LinearProbe<LPTestConfig1> CollisionStrategy;
};
typedef LPTestConfig1::CollisionStrategy CS1;

struct LPTestConfig2
{
	enum { max_size = 2 };
	typedef int KeyType;
	typedef int DataType;
	typedef SimpleHash<LPTestConfig2> HashFn;
	typedef LinearProbe<LPTestConfig2> CollisionStrategy;
};
typedef LPTestConfig2::CollisionStrategy CS2;

typedef LinearProbingHashtable<10, int, int>::CollisionStrategy CS3;

struct LPTestConfig4
{
	enum { max_size = 200 };
	typedef int KeyType;
	typedef int DataType;
	typedef SimpleModuloHash<LPTestConfig4> HashFn;
	typedef LinearProbe<LPTestConfig4> CollisionStrategy;
};
typedef LPTestConfig4::CollisionStrategy CS4;

struct LPTestConfig5
{
	enum { max_size = 32 };
	typedef int KeyType;
	typedef int DataType;
	typedef SimpleBitMaskHash<LPTestConfig5> HashFn;
	typedef LinearProbe<LPTestConfig5> CollisionStrategy;
};
typedef LPTestConfig5::CollisionStrategy CS5;

struct LPTestConfig6
{
	enum { max_size = 200 };
	typedef int KeyType;
	typedef int DataType;
	typedef SimpleModuloHash<LPTestConfig6> HashFn;
	typedef Chaining<LPTestConfig6> CollisionStrategy;
};
typedef LPTestConfig6::CollisionStrategy CS6;

BOOST_AUTO_TEST_CASE( cses )
{
    test_suite* test = BOOST_TEST_SUITE( "Collision Strategy Tests" );
	typedef boost::mpl::list<CS1, CS2, CS3, CS4, CS5, CS6> strats;

    test->add( BOOST_TEST_CASE_TEMPLATE( cs1, strats ) );
    test->add( BOOST_TEST_CASE_TEMPLATE( cs2, strats ) );
    test->add( BOOST_TEST_CASE_TEMPLATE( cs3, strats ) );
    test->add( BOOST_TEST_CASE_TEMPLATE( cs4, strats ) );
    test->add( BOOST_TEST_CASE_TEMPLATE( cs5, strats ) );
    test->add( BOOST_TEST_CASE_TEMPLATE( cs6, strats ) );
    test->add( BOOST_TEST_CASE_TEMPLATE( cs7, strats ) );
    test->add( BOOST_TEST_CASE_TEMPLATE( cs8, strats ) );
    test->add( BOOST_TEST_CASE_TEMPLATE( cs9, strats ) );

	boost::unit_test::framework::run( test );

}
